using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using ZoneFiveSoftware.Common.Data;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Data.Measurement;
using ZoneFiveSoftware.Common.Visuals;
using ZoneFiveSoftware.Common.Visuals.Chart;
using FilteredStatistics.Common;
using FilteredStatistics.Controller;
using System.Diagnostics;

namespace FilteredStatistics.Common.Controller
{
    class SpeedDataTrackProvider : IActivityDataTrackProvider
    {
        public SpeedDataTrackProvider()
        {
            PluginMain.ZoneCategoryListChanged += new PluginMain.ZoneCategoryChangedEventHandler(OnZoneCategoryChanged);
            m_ActivityDataChangedHelper.PropertyChanged += new PropertyChangedEventHandler(OnActivityDataChanged);
        }

        void OnZoneCategoryChanged(object sender, IZoneCategory category)
        {
            if (DataTrackChanged != null)
            {
                DataTrackChanged(this, new PropertyChangedEventArgs("AxisStripes"));
            }
        }

        void OnActivityDataChanged(object sender, PropertyChangedEventArgs e)
        {
            bool trackNeedsRefresh = false;
            bool axisNeedsRefresh = false;
            bool stripesNeedsRefresh = false;

            if (e.PropertyName == "Activity.Category")
            {
                trackNeedsRefresh = true;
                axisNeedsRefresh = true;
                stripesNeedsRefresh = true;
            }
            else if (e.PropertyName == "Activity.Duration")
            {
                trackNeedsRefresh = true;
            }
            else if (e.PropertyName == "ActivityCategory.DistanceUnits")
            {
                trackNeedsRefresh = true;
                axisNeedsRefresh = true;
                stripesNeedsRefresh = true;
            }
            else if (e.PropertyName == "ActivityCategory.SpeedZone")
            {
                stripesNeedsRefresh = true;
            }
            else if (e.PropertyName == "ActivityCategory.UseParentSettings")
            {
                trackNeedsRefresh = true;
                axisNeedsRefresh = true;
                stripesNeedsRefresh = true;
            }
            else if (e.PropertyName == "ActivityCategory.UseSystemLengthUnits")
            {
                trackNeedsRefresh = true;
                axisNeedsRefresh = true;
                stripesNeedsRefresh = true;
            }
            else if (e.PropertyName == "AnalysisSettings.SpeedSmoothingSeconds")
            {
                trackNeedsRefresh = true;
            }

            if (DataTrackChanged != null)
            {
                if (trackNeedsRefresh)
                {
                    DataTrackChanged(this, new PropertyChangedEventArgs("SmoothedDataTrack"));
                }

                if (axisNeedsRefresh)
                {
                    DataTrackChanged(this, new PropertyChangedEventArgs("Axis"));
                }

                if (stripesNeedsRefresh)
                {
                    DataTrackChanged(this, new PropertyChangedEventArgs("AxisStripes"));
                }
            }
        }

#region IActivityDataTrackProvider Members

        public Guid ReferenceId
        {
            get { return new Guid("2e9f7e63-d671-4527-81f9-450741721dfa"); }
        }

        public bool IsPrimaryDataTrack
        {
            get { return true; }
        }

        public IActivity Activity
        {
            set
            {
                if (m_Activity != value)
                {
                    m_Activity = value;
                    m_ActivityDataChangedHelper.Activity = value;
                }
            }
        }

        public string YAxisLabel
        {
            get
            {
                string yAxisLabel = String.Empty;

                if (m_Activity != null && m_Activity.Category.SpeedUnits == Speed.Units.Pace)
                {
                    yAxisLabel = CommonResources.Text.LabelPace;
                }
                else
                {
                    yAxisLabel = CommonResources.Text.LabelSpeed;
                }

                return yAxisLabel;
            }
        }

        public string YAxisUnitLabel
        {
            get
            {
                string yAxisUnitLabel = String.Empty;

                if (m_Activity != null)
                {
                    yAxisUnitLabel = "(" + Utils.GetMajorSpeedUnitLabelForActivity(m_Activity) + ")";
                }

                return yAxisUnitLabel;
            }
        }

        public Color TrackColor
        {
            get { return Color.FromArgb(32, 74, 135); }
        }

        public IAxisFormatter AxisFormatter 
        {
            get
            {
                if (m_Activity != null && m_Activity.Category.SpeedUnits == Speed.Units.Pace)
                {
                    return new Formatter.SecondsToTime();
                }
                else
                {
                    return new Formatter.General(2);
                }
            }
        }

        public INumericTimeDataSeries SmoothedDataTrack
        {
            get
            {
                if (m_Activity != null)
                {
                    INumericTimeDataSeries tempResult = ActivityInfoCache.Instance.GetInfo(m_Activity).SmoothedSpeedTrack;

                    // Value is in m/sec so convert to the right unit and to
                    //  pace if necessary
                    INumericTimeDataSeries result = new NumericTimeDataSeries();
                    foreach (ITimeValueEntry<float> entry in tempResult)
                    {
                        double temp = Length.Convert(entry.Value, Length.Units.Meter, Utils.MajorLengthUnit(m_Activity.Category.DistanceUnits)) * Constants.SecondsPerHour;

                        if (m_Activity.Category.SpeedUnits == Speed.Units.Pace)
                        {
                            // Convert to pace and then in second
                            temp = Utils.SpeedToPace(temp) * Constants.SecondsPerMinute;
                        }

                        result.Add(tempResult.EntryDateTime(entry), (float)temp);
                    }

                    return result;
                }

                return null;
            }
        }

        public IList<Guid> DataTrackZoneGuids
        {
            get
            {
                List<Guid> result = new List<Guid>();

                foreach (IZoneCategory category in PluginMain.GetApplication().Logbook.SpeedZones)
                {
                    result.Add(new Guid(category.ReferenceId));
                }

                return result;
            }
        }

        public Guid DefaultZone
        {
            get
            {
                if (m_Activity != null)
                {
                    return new Guid(m_Activity.Category.SpeedZone.ReferenceId);
                }
                else
                {
                    return new Guid(PluginMain.GetApplication().Logbook.SpeedZones[0].ReferenceId);
                }
            }
        }

        public string GetDataTrackZoneName(Guid zoneId)
        {
            foreach (IZoneCategory category in PluginMain.GetApplication().Logbook.SpeedZones)
            {
                if (category.ReferenceId.Equals(zoneId.ToString()))
                {
                    return category.Name;
                }
            }

            return String.Empty;
        }

        public IList<AxisStripe> GetDataTrackZones(Guid zoneId)
        {
            List<AxisStripe> result = new List<AxisStripe>();

            foreach (IZoneCategory category in PluginMain.GetApplication().Logbook.SpeedZones)
            {
                if (category.ReferenceId.Equals(zoneId.ToString()))
                {
                    foreach (INamedLowHighZone zone in category.Zones)
                    {
                        double lower;
                        double upper;

                        if (m_Activity != null && m_Activity.Category.SpeedUnits == Speed.Units.Pace)
                        {
                            Length.Units destinationUnit = Utils.MajorLengthUnit(m_Activity.Category.DistanceUnits);

                            lower = Utils.SpeedToPace(Length.Convert(zone.High, Length.Units.Meter, destinationUnit) * Constants.MinutesPerHour);
                            upper = Utils.SpeedToPace(Length.Convert(zone.Low, Length.Units.Meter, destinationUnit) * Constants.MinutesPerHour);
                        }
                        else
                        {
                            Length.Units destinationUnit = Length.Units.Kilometer;

                            if (m_Activity != null)
                            {
                                destinationUnit = Utils.MajorLengthUnit(m_Activity.Category.DistanceUnits);
                            }

                            lower = Length.Convert(zone.Low, Length.Units.Meter, destinationUnit) * Constants.SecondsPerHour;
                            upper = Length.Convert(zone.High, Length.Units.Meter, destinationUnit) * Constants.SecondsPerHour;
                        }

                        AxisStripe newStripe = new AxisStripe(lower, upper, Color.FromArgb(16, 0, 0, 0));

                        newStripe.Name = zone.Name;
                        result.Add(newStripe);
                    }
                }
            }

            return result;
        }

        public event PropertyChangedEventHandler DataTrackChanged;

#endregion

        private IActivity m_Activity = null;
        private ActivityDataChangedHelper m_ActivityDataChangedHelper = new ActivityDataChangedHelper(null);
    }
}
